package luke.ui.components;

import java.awt.*;
import java.awt.event.*;
import java.io.File;
import javax.swing.*;
import java.awt.Dialog;

import luke.core.controller.PlayController;
import luke.core.utils.SvgIconLoader;
import luke.core.utils.PlaybackStateManager;
import luke.core.utils.LanguageManager; // 新增：导入LanguageManager

/**
 * 播放控制面板类
 * 职责：只负责状态的显示和将用户操作转发给播放控制器
 */
public class PlayPanel extends JPanel {
    // 播放控制相关字段
    private JLabel currentFileLabel;// 当前播放文件标签
    private JSlider playbackSlider;// 播放进度条
    private JLabel currentTimeLabel;// 当前播放进度标签
    private JLabel totalTimeLabel;// 总播放时长标签
    private JLabel stopOrPlayerButton;// 停止播放
    private JLabel previousButton;// 上一曲
    private JLabel nextButton;// 下一曲
    private JLabel beatToggleButton;// 鼓点开关
    private boolean isSliderDragging = false;// 进度条是否正在拖动
    private File currentlyPlayingFile;// 正在播放的文件

    // 状态跟踪字段
    private boolean isPlaying = false;
    private long savedPosition = 0;

    // 波形面板
    private RealtimeWaveformPanel waveformPanel;

    // 鼓点状态跟踪
    private boolean isBeatEnabled = false;

    // BPM和偏移量输入控件
    private JTextField bpmInputField;
    private JTextField offsetInputField;
    private JButton updateBeatsButton;
    private JButton restoreBeatsButton;
    private JButton saveBeatsButton;
    private JButton tapBeatButton;
    private JButton offsetCorrectionButton; // 新增的偏移校正按钮
    private JPanel bpmOffsetPanel;

    // 手敲鼓点相关字段
    private java.util.List<Long> tapTimes = new java.util.ArrayList<>();
    private PlaybackStateManager playbackStateManager;
    // 添加PlayController引用
    private PlayController playController;
    
    // 添加用于记录原始BPM和偏移量的字段
    private Double originalBpm = null;
    private Integer originalOffset = null;
    
    // 音量控制相关字段
    private JLabel volumeButton; // 音量按钮
    private JPopupMenu volumePopup; // 音量弹出菜单
    private JSlider volumeSlider; // 音量滑块
    
    // 节拍音量控制相关字段
    private JLabel beatVolumeButton; // 节拍音量按钮
    private JPopupMenu beatVolumePopup; // 节拍音量弹出菜单
    private JSlider beatVolumeSlider; // 节拍音量滑块
    
    // 用于保存原始鼓点音量的字段
    private Float originalBeatVolume = null; // 使用Float包装类以便区分未设置状态(null)
    
    // 节拍音效控制相关字段
    private JLabel beatSoundButton; // 节拍音效按钮
    private JPopupMenu beatSoundPopup; // 节拍音效弹出菜单
    private JList<String> beatSoundList; // 节拍音效列表

    // 背景音量控制相关字段
    private JLabel backgroundVolumeButton; // 背景音量按钮
    private JPopupMenu backgroundVolumePopup; // 背景音量弹出菜单
    private JSlider backgroundVolumeSlider; // 背景音量滑块
    
    // 添加LanguageManager引用
    private LanguageManager languageManager;
    
    public PlayPanel() {
        // 初始化LanguageManager
        this.languageManager = LanguageManager.getInstance();
        
        // 获取PlayController单例实例
        this.playController = PlayController.getInstance();
        playbackStateManager = PlaybackStateManager.getInstance();
        
        // 加载并设置保存的音量值
        float savedVolume = loadSavedVolume();
        playbackStateManager.setVolume(savedVolume);
        // 设置音量滑块的初始值（这会触发滑块事件监听器，所以不需要再手动调用音量控制方法）
        if (volumeSlider != null) {
            volumeSlider.setValue((int)(savedVolume * 100));
        }
        
        // 加载并设置保存的节拍音量值
        float savedBeatVolume = loadSavedBeatVolume();
        playbackStateManager.setBeatVolume(savedBeatVolume);
        
        // 设置节拍音量滑块的初始值（这会触发滑块事件监听器，所以不需要再手动调用音量控制方法）
        if (beatVolumeSlider != null) {
            beatVolumeSlider.setValue((int)(savedBeatVolume * 100));
        }
        
        // 加载并设置保存的背景音量值
        float backgroundVolume = loadSavedBackgroundVolume();
        playbackStateManager.setBackgroundVolume(backgroundVolume);
        
        // 设置背景音量滑块的初始值（这会触发滑块事件监听器，所以不需要再手动调用音量控制方法）
        if (backgroundVolumeSlider != null) {
            backgroundVolumeSlider.setValue((int)(backgroundVolume * 100));
        }
        
        // 加载并设置保存的背景音量值
        float savedBackgroundVolume = loadSavedBackgroundVolume();
        playbackStateManager.setBackgroundVolume(savedBackgroundVolume);
        
        // 加载并设置保存的节拍音效类型
        int savedBeatSoundType = loadSavedBeatSoundType();
        playbackStateManager.setBeatSoundType(savedBeatSoundType);
        
        playbackStateManager.addListener(new PlaybackStateManager.PlaybackStateListener() {
            @Override
            public void onPlaybackStateChanged(boolean isPlaying) {
                if (isPlaying) {
                    setPlayingIcon();
                    // 播放状态时，提示应该显示"点击暂停播放"
                    stopOrPlayerButton.setToolTipText(languageManager.getPanelText("playback.pause.tip"));
                } else {
                    setPausedIcon();
                    // 暂停状态时，提示应该显示"点击播放音频"
                    stopOrPlayerButton.setToolTipText(languageManager.getPanelText("playback.play.tip"));
                }
            }

            @Override
            public void onPositionChanged(long positionMs) {
                setCurrentTimeLabel(positionMs);
            }

            @Override
            public void onDurationChanged(long durationMs) {
                setTotalTimeLabel(durationMs);
            }

            @Override
            public void onFileChanged(File file) {
                setCurrentFileLabel(file);
                // 清理手敲鼓点记录
                tapTimes.clear();
                // 清除记录的原始BPM和偏移量
                originalBpm = null;
                originalOffset = null;
                // 恢复原始鼓点音量（如果之前被临时设置为0）
                restoreOriginalBeatVolume();
                // 显示波形图中的鼓点线条（当文件改变时清除手敲鼓点记录）
                playController.showBeatLines();
            }
        });
        this.playbackStateManager.addListener(new PlaybackStateManager.BeatEnableListener() {
            @Override
            public void onBeatEnabledChanged(boolean enabled) {
                //鼓点启用状态时,打开鼓点设置面板
                if (enabled) {
                    // 鼓点启用时,切换按钮图标
                    SvgIconLoader.setButtonIcon(beatToggleButton, "/ico/beatsON.svg", 20, 20);
                    // 鼓点已启用，提示应该显示"点击禁用鼓点"
                    beatToggleButton.setToolTipText(languageManager.getPanelText("playback.beat.off"));
                } else {
                    // 鼓点禁用时,切换按钮图标
                    SvgIconLoader.setButtonIcon(beatToggleButton, "/ico/beatsOFF.svg", 20, 20);
                    // 鼓点已禁用，提示应该显示"点击启用鼓点"
                    beatToggleButton.setToolTipText(languageManager.getPanelText("playback.beat.on"));
                }
                if (enabled) {
                    bpmOffsetPanel.setVisible(true);
                    // 鼓点启用时显示节拍音量和节拍音效按钮
                    beatVolumeButton.setVisible(true);
                    beatSoundButton.setVisible(true);
                } else {
                    bpmOffsetPanel.setVisible(false);
                    // 鼓点禁用时隐藏节拍音量和节拍音效按钮
                    beatVolumeButton.setVisible(false);
                    beatSoundButton.setVisible(false);
                }
            }
        });

        // 添加元数据监听器，监听BPM和偏移量变化
        this.playbackStateManager.addListener(new PlaybackStateManager.MetadataListener() {
            @Override
            public void onBpmChanged(double bpm) {
                // 当BPM发生变化时，更新BPM输入框
                bpmInputField.setText(String.format("%.2f", bpm));
            }

            @Override
            public void onBeatOffsetChanged(int offset) {
                // 当偏移量发生变化时，更新偏移量输入框
                offsetInputField.setText(String.valueOf(offset));
            }
        });

        // 添加保存成功状态监听器
        this.playbackStateManager.addListener(new PlaybackStateManager.SaveSuccessListener() {
            @Override
            public void onSaveSuccessChanged(boolean successful) {
                // 当保存成功状态发生变化时，显示相应的提示
                if (successful) {
                    showMessageDialog("鼓点数据保存成功", JOptionPane.INFORMATION_MESSAGE);
                }
            }
        });

        initializeComponents();
        setupLayout();
        setupBpmOffsetPanel();
        setupEventListeners();
    }

    /**
     * 初始化组件
     */
    private void initializeComponents() {
        // 初始化波形面板（不直接创建AdvancedAudioPlayer）
        waveformPanel = new RealtimeWaveformPanel();
        waveformPanel.setPreferredSize(new Dimension(800, 150));

        // 初始化标签
        currentFileLabel = new JLabel(languageManager.getPanelText("playback.original.speed", languageManager.getString("playback.no.file")));
        currentFileLabel.setFont(currentFileLabel.getFont().deriveFont(12.0f));
        currentFileLabel.setForeground(new Color(27, 121, 148));

        // 初始化进度控件
        playbackSlider = new JSlider(0, 1000, 0); // 修改最大值为1000以提高精度
        playbackSlider.setEnabled(true); // 启用滑块以允许用户交互
        currentTimeLabel = new JLabel("00:00");
        totalTimeLabel = new JLabel("00:00");

        // 初始化控制按钮
        previousButton = new JLabel();
        previousButton.setEnabled(true);
        SvgIconLoader.setButtonIcon(previousButton, "/ico/上一曲.svg", 20, 20);
        previousButton.setCursor(new Cursor(Cursor.HAND_CURSOR));
        previousButton.setToolTipText(languageManager.getPanelText("playback.previous"));

        stopOrPlayerButton = new JLabel();
        stopOrPlayerButton.setEnabled(true);
        SvgIconLoader.setButtonIcon(stopOrPlayerButton, "/ico/播放.svg", 20, 20);
        stopOrPlayerButton.setCursor(new Cursor(Cursor.HAND_CURSOR));
        // 初始化时是暂停状态，提示应该显示"点击播放音频"
        stopOrPlayerButton.setToolTipText(languageManager.getPanelText("playback.play.tip"));

        nextButton = new JLabel();
        nextButton.setEnabled(true);
        SvgIconLoader.setButtonIcon(nextButton, "/ico/下一曲.svg", 20, 20);
        nextButton.setCursor(new Cursor(Cursor.HAND_CURSOR));
        nextButton.setToolTipText(languageManager.getPanelText("playback.next"));

        beatToggleButton = new JLabel();
        beatToggleButton.setEnabled(true);
        SvgIconLoader.setButtonIcon(beatToggleButton, "/ico/beatsOFF.svg", 20, 20);
        beatToggleButton.setCursor(new Cursor(Cursor.HAND_CURSOR));
        // 初始化时鼓点是禁用状态，提示应该显示"点击启用鼓点"
        beatToggleButton.setToolTipText(languageManager.getPanelText("playback.beat.on"));

        // 初始化音量控制组件
        volumeButton = new JLabel();
        volumeButton.setEnabled(true);
        SvgIconLoader.setButtonIcon(volumeButton, "/ico/音量.svg", 20, 20);
        volumeButton.setCursor(new Cursor(Cursor.HAND_CURSOR));
        volumeButton.setToolTipText(languageManager.getPanelText("playback.volume"));
        
        // 初始化音量弹出菜单和滑块
        volumePopup = new JPopupMenu();
        volumePopup.setLayout(new BorderLayout());
        volumeSlider = new JSlider(0, 100, (int)(loadSavedVolume() * 100)); // 使用保存的音量值作为初始值
        volumeSlider.setOrientation(JSlider.VERTICAL);
        volumeSlider.setPreferredSize(new Dimension(40, 100));
        // 为音量滑块添加鼠标滚轮支持
        volumeSlider.addMouseWheelListener(e -> {
            int notches = e.getWheelRotation();
            int value = volumeSlider.getValue();
            // 滚轮向上滚动减小音量，向下滚动增大音量
            if (notches < 0) {
                volumeSlider.setValue(Math.min(value + 2, volumeSlider.getMaximum()));
            } else {
                volumeSlider.setValue(Math.max(value - 2, volumeSlider.getMinimum()));
            }
        });
        volumePopup.add(volumeSlider, BorderLayout.CENTER);
        volumePopup.setBorder(BorderFactory.createTitledBorder(languageManager.getPanelText("playback.volume")));

        // 初始化鼓点和背景音量控制组件
        beatVolumeButton = new JLabel();
        beatVolumeButton.setEnabled(true);
        SvgIconLoader.setButtonIcon(beatVolumeButton, "/ico/节拍音量.svg", 20, 20);
        beatVolumeButton.setCursor(new Cursor(Cursor.HAND_CURSOR));
        beatVolumeButton.setToolTipText(languageManager.getPanelText("playback.beat.volume"));
        
        // 初始化鼓点和背景音量弹出菜单和滑块
        beatVolumePopup = new JPopupMenu();
        beatVolumePopup.setLayout(new BorderLayout());
        
        // 创建包含两个滑块的面板
        JPanel volumeSlidersPanel = new JPanel();
        volumeSlidersPanel.setLayout(new BoxLayout(volumeSlidersPanel, BoxLayout.X_AXIS));
        
        // 初始化鼓点音量滑块
        beatVolumeSlider = new JSlider(0, 100, (int)(loadSavedBeatVolume() * 100)); // 使用保存的节拍音量值作为初始值
        beatVolumeSlider.setOrientation(JSlider.VERTICAL);
        beatVolumeSlider.setPreferredSize(new Dimension(40, 100));
        JPanel beatVolumePanel = new JPanel(new BorderLayout());
        beatVolumePanel.add(new JLabel(languageManager.getPanelText("playback.beat.volume.beat"), JLabel.CENTER), BorderLayout.NORTH);
        beatVolumePanel.add(beatVolumeSlider, BorderLayout.CENTER);
        
        // 初始化背景音量滑块
        backgroundVolumeSlider = new JSlider(0, 100, (int)(loadSavedBackgroundVolume() * 100));
        backgroundVolumeSlider.setOrientation(JSlider.VERTICAL);
        backgroundVolumeSlider.setPreferredSize(new Dimension(40, 100));
        JPanel backgroundVolumePanel = new JPanel(new BorderLayout());
        backgroundVolumePanel.add(new JLabel(languageManager.getPanelText("playback.beat.volume.background"), JLabel.CENTER), BorderLayout.NORTH);
        backgroundVolumePanel.add(backgroundVolumeSlider, BorderLayout.CENTER);
        
        volumeSlidersPanel.add(beatVolumePanel);
        volumeSlidersPanel.add(Box.createHorizontalStrut(10)); // 添加间距
        volumeSlidersPanel.add(backgroundVolumePanel);
        
        beatVolumePopup.add(volumeSlidersPanel, BorderLayout.CENTER);
        beatVolumePopup.setBorder(BorderFactory.createTitledBorder(languageManager.getPanelText("playback.beat.volume")));

        // 初始化节拍音效控制组件
        beatSoundButton = new JLabel();
        beatSoundButton.setEnabled(true);
        SvgIconLoader.setButtonIcon(beatSoundButton, "/ico/节拍音效.svg", 20, 20);
        beatSoundButton.setCursor(new Cursor(Cursor.HAND_CURSOR));
        beatSoundButton.setToolTipText(languageManager.getPanelText("playback.beat.sound"));
        
        // 初始化节拍音效弹出菜单和列表
        beatSoundPopup = new JPopupMenu();
        beatSoundPopup.setLayout(new BorderLayout());
        String[] soundOptions = {
            languageManager.getPanelText("playback.beat.sound.default"),
            languageManager.getPanelText("playback.beat.sound.bubble"),
            languageManager.getPanelText("playback.beat.sound.drum"),
            languageManager.getPanelText("playback.beat.sound.triangle"),
            languageManager.getPanelText("playback.beat.sound.wood"),
            languageManager.getPanelText("playback.beat.sound.sword")
        };
        beatSoundList = new JList<>(soundOptions);
        beatSoundList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        beatSoundList.setSelectedIndex(loadSavedBeatSoundType()); // 使用保存的节拍音效类型作为初始选择
        beatSoundList.setPreferredSize(new Dimension(100, 120));
        beatSoundPopup.add(new JScrollPane(beatSoundList), BorderLayout.CENTER);
        beatSoundPopup.setBorder(BorderFactory.createTitledBorder(languageManager.getPanelText("playback.beat.sound")));

        // 背景音量滑块已整合到鼓点音量弹出菜单中

        // 初始化BPM和偏移量控件
        bpmOffsetPanel = new JPanel();
        bpmOffsetPanel.setLayout(new BoxLayout(bpmOffsetPanel, BoxLayout.Y_AXIS));
        bpmOffsetPanel.setBorder(null);
        bpmInputField = new JTextField(8);
        offsetInputField = new JTextField(8);
        updateBeatsButton = new JButton(languageManager.getPanelText("playback.update.beats"));
        restoreBeatsButton = new JButton(languageManager.getPanelText("playback.restore.beats"));
        saveBeatsButton = new JButton(languageManager.getPanelText("playback.save.beats"));
        tapBeatButton = new JButton(languageManager.getPanelText("playback.tap.beats"));
        tapBeatButton.setToolTipText(languageManager.getPanelText("playback.tap.beats.tip")); // 更新手敲鼓点按钮提示
        offsetCorrectionButton = new JButton(languageManager.getPanelText("playback.offset.correct")); // 初始化偏移校正按钮
        offsetCorrectionButton.setToolTipText(languageManager.getPanelText("playback.offset.correct.tip")); // 更新偏移校正按钮提示
        bpmOffsetPanel.setVisible(false);
        
        // 节拍音量和节拍音效按钮默认隐藏
        beatVolumeButton.setVisible(false);
        beatSoundButton.setVisible(false);
    }

    /**
     * 设置布局
     */
    private void setupLayout() {
        setLayout(new BorderLayout(0, 5));
        setBorder(BorderFactory.createTitledBorder(languageManager.getPanelText("playback.title")));
        setMinimumSize(new Dimension(300, 250));
        setPreferredSize(new Dimension(800, 350));
        setMaximumSize(new Dimension(1000, 500));

        // 添加波形面板
        add(waveformPanel, BorderLayout.CENTER);

        // 创建顶部面板用于放置文件标签
        JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        topPanel.add(currentFileLabel);
        add(topPanel, BorderLayout.NORTH);

        // 创建播放进度面板
        JPanel progressPanel = new JPanel(new BorderLayout());
        progressPanel.add(currentTimeLabel, BorderLayout.WEST);
        progressPanel.add(playbackSlider, BorderLayout.CENTER);
        progressPanel.add(totalTimeLabel, BorderLayout.EAST);

        // 播放控制面板
        JPanel playerControlPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
        playerControlPanel.add(previousButton);
        playerControlPanel.add(stopOrPlayerButton);
        playerControlPanel.add(nextButton);
        playerControlPanel.add(beatToggleButton);
        playerControlPanel.add(volumeButton); // 添加音量按钮到控制面板
        playerControlPanel.add(beatVolumeButton); // 添加鼓点和背景音量按钮到控制面板
        playerControlPanel.add(beatSoundButton); // 添加节拍音效按钮到控制面板

        // BPM和偏移量输入面板
        setupBpmOffsetPanel();

        // 创建底部面板
        JPanel bottomPanel = new JPanel();
        bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.Y_AXIS));

        JPanel progressWrapper = new JPanel(new BorderLayout());
        progressWrapper.add(progressPanel, BorderLayout.CENTER);
        bottomPanel.add(progressWrapper);

        JPanel bpmOffsetWrapper = new JPanel(new BorderLayout());
        bpmOffsetWrapper.add(bpmOffsetPanel, BorderLayout.CENTER);
        bottomPanel.add(bpmOffsetWrapper);

        JPanel controlWrapper = new JPanel(new FlowLayout(FlowLayout.CENTER));
        controlWrapper.add(playerControlPanel);
        bottomPanel.add(controlWrapper);

        add(bottomPanel, BorderLayout.SOUTH);
    }

    /**
     * 设置BPM和偏移量面板
     */
    private void setupBpmOffsetPanel() {
        // 确保面板是空的，避免重复添加组件
        bpmOffsetPanel.removeAll();
        bpmOffsetPanel.setLayout(new BoxLayout(bpmOffsetPanel, BoxLayout.Y_AXIS));
        bpmOffsetPanel.setBorder(null);

        // 创建第一行面板（输入框）
        JPanel inputPanel = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5, 10, 5, 10);

        gbc.gridx = 0;
        gbc.gridy = 0;
        inputPanel.add(new JLabel(languageManager.getPanelText("playback.bpm")), gbc);
        gbc.gridx = 1;
        gbc.gridy = 0;
        inputPanel.add(bpmInputField, gbc);

        gbc.gridx = 2;
        gbc.gridy = 0;
        inputPanel.add(new JLabel(languageManager.getPanelText("playback.offset")), gbc);
        gbc.gridx = 3;
        gbc.gridy = 0;
        inputPanel.add(offsetInputField, gbc);

        // 创建第二行面板（按钮）
        JPanel buttonPanel = new JPanel(new GridBagLayout());
        GridBagConstraints gbc2 = new GridBagConstraints();
        gbc2.insets = new Insets(5, 10, 5, 10);

        gbc2.gridx = 0;
        gbc2.gridy = 0;
        buttonPanel.add(updateBeatsButton, gbc2);
        gbc2.gridx = 1;
        gbc2.gridy = 0;
        buttonPanel.add(restoreBeatsButton, gbc2);
        gbc2.gridx = 2;
        gbc2.gridy = 0;
        buttonPanel.add(saveBeatsButton, gbc2);
        gbc2.gridx = 3;
        gbc2.gridy = 0;
        buttonPanel.add(tapBeatButton, gbc2);
        gbc2.gridx = 4;
        gbc2.gridy = 0;
        buttonPanel.add(offsetCorrectionButton, gbc2); // 添加偏移校正按钮

        bpmOffsetPanel.add(inputPanel);
        bpmOffsetPanel.add(buttonPanel);
    }

    /**
     * 设置事件监听器
     */
    private void setupEventListeners() {
        // 滑块事件监听器
        playbackSlider.addChangeListener(e -> {
            JSlider source = (JSlider) e.getSource();
            if (source.getValueIsAdjusting()) {
                // 用户正在拖动滑块，更新时间显示但不跳转播放位置
                if (!isSliderDragging) {
                    isSliderDragging = true;
                }
                // 更新时间标签显示
                long positionMs = (long) (source.getValue() / (double) source.getMaximum() * playbackStateManager.getTotalDurationMs());
                currentTimeLabel.setText(formatTime(positionMs));
            } else {
                // 用户释放滑块，执行跳转
                if (isSliderDragging) {
                    isSliderDragging = false;
                    // 计算当前进度条位置对应的时间
                    double position = source.getValue() / (double) source.getMaximum();
                    // 告诉控制器进行时间跳转
                    playController.seekTo(position);
                }
            }
        });

        // 音量滑块事件监听器
        volumeSlider.addChangeListener(e -> {
            JSlider source = (JSlider) e.getSource();
            // 实时更新音量，无论是否正在拖动
            float volume = source.getValue() / 100.0f;
            playController.setMasterVolume(volume);
            // 保存音量设置
            try {
                luke.core.config.AppDataManager appDataManager = luke.core.config.AppDataManager.getInstance();
                appDataManager.setVolume(volume);
            } catch (Exception ex) {
                // 忽略保存错误
            }
        });

        // 鼓点音量滑块事件监听器
        beatVolumeSlider.addChangeListener(e -> {
            JSlider source = (JSlider) e.getSource();
            // 只有在用户释放滑块时才更新鼓点音量，避免频繁刷新造成卡顿
            if (!source.getValueIsAdjusting()) {
                float beatVolume = source.getValue() / 100.0f;
                // 调用控制器的方法更新鼓点音量
                playController.setBeatVolume(beatVolume);
                // 保存鼓点音量设置
                try {
                    luke.core.config.AppDataManager appDataManager = luke.core.config.AppDataManager.getInstance();
                    appDataManager.setBeatVolume(beatVolume);
                } catch (Exception ex) {
                    // 忽略保存错误
                }
            }
        });
        
        // 背景音量滑块事件监听器
        backgroundVolumeSlider.addChangeListener(e -> {
            JSlider source = (JSlider) e.getSource();
            // 只有在用户释放滑块时才更新背景音量，避免频繁刷新造成卡顿
            if (!source.getValueIsAdjusting()) {
                float backgroundVolume = source.getValue() / 100.0f;
                playController.setBackgroundVolume(backgroundVolume);
                // 保存背景音量设置
                try {
                    luke.core.config.AppDataManager appDataManager = luke.core.config.AppDataManager.getInstance();
                    appDataManager.setBackgroundVolume(backgroundVolume);
                } catch (Exception ex) {
                    // 忽略保存错误
                }
            }
        });
        
        // 节拍音效列表选择事件监听器
        beatSoundList.addListSelectionListener(e -> {
            if (!e.getValueIsAdjusting()) {
                // 调用控制器的方法更新节拍音效类型
                playController.setBeatSoundType(beatSoundList.getSelectedIndex());
                // 保存节拍音效类型设置
                try {
                    luke.core.config.AppDataManager appDataManager = luke.core.config.AppDataManager.getInstance();
                    appDataManager.setBeatSoundType(beatSoundList.getSelectedIndex());
                } catch (Exception ex) {
                    // 忽略保存错误
                }
            }
        });

        // 按钮事件监听器
        previousButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                playController.playPreviousTrack();//告诉播放器播放上一个文件
            }
        });

        stopOrPlayerButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                playController.togglePlayback();//告诉控制器切换播放状态
            }
        });

        nextButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {

                playController.playNextTrack();//告诉控制器播放下一个文件
            }
        });

        beatToggleButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                // 检查是否有正在播放的文件
                if (playbackStateManager.getCurrentFile() == null) {
                    // 没有播放文件时显示提示
                    JOptionPane pane = new JOptionPane(
                        languageManager.getString("playback.no.file.to.enable.beat"), 
                        JOptionPane.WARNING_MESSAGE);
                    JDialog dialog = pane.createDialog(PlayPanel.this, languageManager.getString("playback.enable.beat"));
                    dialog.setLocationRelativeTo(null); // 居中显示在屏幕中央
                    // 设置对话框图标
                    try {
                        Image icon = new ImageIcon(getClass().getResource("/ico/run_bpm.png")).getImage();
                        dialog.setIconImage(icon);
                    } catch (Exception ex) {
                        System.err.println("无法加载对话框图标: " + ex.getMessage());
                    }
                    dialog.setVisible(true);
                    return;
                }
                playController.toggleBeatEnabled();//告诉控制器切换鼓点开关状态
            }
        });

        // 音量按钮事件监听器
        volumeButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                // 在音量按钮下方显示音量控制弹出菜单
                volumePopup.show(volumeButton, 
                    volumeButton.getWidth() / 2 - volumePopup.getPreferredSize().width / 2, 
                    -volumePopup.getPreferredSize().height);
            }
        });
        
        // 节拍音量按钮事件监听器
        beatVolumeButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                // 在节拍音量按钮下方显示节拍音量控制弹出菜单
                beatVolumePopup.show(beatVolumeButton, 
                    beatVolumeButton.getWidth() / 2 - beatVolumePopup.getPreferredSize().width / 2, 
                    -beatVolumePopup.getPreferredSize().height);
            }
        });
        
        // 节拍音效按钮事件监听器
        beatSoundButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                // 在节拍音效按钮下方显示节拍音效选择弹出菜单
                beatSoundPopup.show(beatSoundButton, 
                    beatSoundButton.getWidth() / 2 - beatSoundPopup.getPreferredSize().width / 2, 
                    -beatSoundPopup.getPreferredSize().height);
            }
        });
        
        // 背景音量控制已整合到鼓点音量弹出菜单中

        // BPM输入框事件监听器
        bpmInputField.addFocusListener(new FocusAdapter() {
            @Override
            public void focusLost(FocusEvent e) {
                //离开输入框焦点时调用
                //调用BPM输入预处理方法,将输入的BPM归化到60-200以内,并且支持数学上的*/输入
                updateBpmInputField();
            }
        });

        bpmInputField.addActionListener(e -> updateBpmInputField());//按下回车时调用

        // 按钮事件监听器
        updateBeatsButton.addActionListener(e -> updateBeats());//调用控制器更新鼓点);
        restoreBeatsButton.addActionListener(e -> restoreBeats());//调用控制器恢复鼓点
        saveBeatsButton.addActionListener(e -> {
            // 清除手敲鼓点记录
            tapTimes.clear();
            // 恢复原始鼓点音量（如果之前被临时设置为0）
            restoreOriginalBeatVolume();
            // 清除记录的原始BPM和偏移量
            originalBpm = null;
            originalOffset = null;
            playController.saveBeats(new PlayController.BeatsData(playbackStateManager.getBpm(), playbackStateManager.getBeatOffset()));
        });//调用控制器保存鼓点
        tapBeatButton.addActionListener(e -> handleTapBeat());//敲击鼓点按钮
        offsetCorrectionButton.addActionListener(e -> handleOffsetCorrection());//偏移校正按钮
    }

    // 偏移校正处理方法
    private void handleOffsetCorrection() {
        System.out.println(languageManager.getString("playback.log.offset.correction.clicked"));
        
        if (playbackStateManager.getCurrentFile() == null) {
            System.out.println(languageManager.getString("playback.log.no.playing.file"));
            return;
        }

        // 还原原始BPM和偏移量到输入框
        if (originalBpm != null) {
            bpmInputField.setText(String.format("%.2f", originalBpm));
        }
        if (originalOffset != null) {
            offsetInputField.setText(String.valueOf(originalOffset));
        }
        
        // 清除手敲鼓点记录
        tapTimes.clear();
        
        // 恢复原始鼓点音量（如果之前被临时设置为0）
        restoreOriginalBeatVolume();
        
        // 清除记录的原始BPM和偏移量
        originalBpm = null;
        originalOffset = null;

        // 使用PlaybackStateManager获取当前播放位置
        long currentPosition = playbackStateManager.getCurrentPositionMs();
        System.out.println(languageManager.getString("playback.log.current.position", currentPosition));

        // 减去100ms的延迟补偿
        currentPosition -= 100;
        if (currentPosition < 0) {
            currentPosition = 0;
        }
        System.out.println(languageManager.getString("playback.log.compensated.position", currentPosition));

        // 重新计算偏移并更新到输入框
        double currentBpm = playbackStateManager.getBpm();
        System.out.println(languageManager.getString("playback.log.current.bpm", currentBpm));
        if (currentBpm > 0) {
            // 从bpm计算出间隔时长
            double beatIntervalMs = 60000.0 / currentBpm;
            System.out.println(languageManager.getString("playback.log.beat.interval", beatIntervalMs));
            // 用当前时长对间隔时长取模得到偏移
            int offset = (int) (currentPosition % beatIntervalMs);
            System.out.println(languageManager.getString("playback.log.calculated.offset", offset));
            offsetInputField.setText(String.valueOf(offset));
            System.out.println(languageManager.getString("playback.log.updated.offset.field"));
            
            // 立即调用控制器更新BPM和偏移量
            PlayController.BeatsData beatsData = new PlayController.BeatsData();
            beatsData.bpm = currentBpm;
            beatsData.offset = offset;
            playController.updateBeatsData(beatsData);
        } else {
            // 如果当前没有BPM值，则直接使用当前位置作为偏移
            System.out.println(languageManager.getString("playback.log.no.bpm.use.position", currentPosition));
            offsetInputField.setText(String.valueOf(currentPosition));
            System.out.println(languageManager.getString("playback.log.updated.offset.field"));
            
            // 立即调用控制器更新BPM和偏移量
            PlayController.BeatsData beatsData = new PlayController.BeatsData();
            beatsData.bpm = currentBpm;
            beatsData.offset = (int) currentPosition;
            playController.updateBeatsData(beatsData);
        }
        
        // 显示波形图中的鼓点线条（当点击偏移校正时）
        playController.showBeatLines();
    }

    //更新鼓点
    private void updateBeats() {
        // 清除手敲鼓点记录
        tapTimes.clear();
        
        // 恢复原始鼓点音量（如果之前被临时设置为0）
        restoreOriginalBeatVolume();
        
        // 清除记录的原始BPM和偏移量
        originalBpm = null;
        originalOffset = null;

        try {
            String bpmText = bpmInputField.getText().trim();
            // 检查BPM输入是否为空
            if (bpmText.isEmpty()) {
                showMessageDialog(languageManager.getPanelText("playback.enter.bpm"));
                return;
            }
            
            double bpm = parseBpmExpression(bpmText);
            // 检查BPM是否为0或负数
            if (bpm <= 0) {
                showMessageDialog(languageManager.getPanelText("playback.invalid.bpm"));
                return;
            }
            
            String offsetText = offsetInputField.getText().trim();
            // 检查偏移量输入是否为空
            if (offsetText.isEmpty()) {
                showMessageDialog(languageManager.getPanelText("playback.enter.offset"));
                return;
            }
            
            int offset = Integer.parseInt(offsetText);
            
            PlayController.BeatsData beatsData = new PlayController.BeatsData();
            beatsData.bpm = bpm;
            beatsData.offset = offset;
            playController.updateBeatsData(beatsData);
            
            // 显示波形图中的鼓点线条（当点击更新鼓点时）
            playController.showBeatLines();
        } catch (NumberFormatException e) {
            showMessageDialog(languageManager.getPanelText("playback.invalid.input"));
        } catch (Exception e) {
            showMessageDialog(languageManager.getString("playback.update.error", e.getMessage()), JOptionPane.ERROR_MESSAGE);
        }
    }

    // 显示消息对话框（居中显示在屏幕中央）
    private void showMessageDialog(String message) {
        showMessageDialog(message, JOptionPane.WARNING_MESSAGE);
    }
    
    private void showMessageDialog(String message, int messageType) {
        JOptionPane pane = new JOptionPane(message, messageType);
        String title;
        switch (messageType) {
            case JOptionPane.ERROR_MESSAGE:
                title = languageManager.getString("panel.common.error.title");
                break;
            case JOptionPane.WARNING_MESSAGE:
                title = languageManager.getString("panel.common.warning.title");
                break;
            case JOptionPane.INFORMATION_MESSAGE:
            default:
                title = languageManager.getString("panel.common.info.title");
                break;
        }
        JDialog dialog = pane.createDialog(this, title);
        dialog.setLocationRelativeTo(null); // 居中显示在屏幕中央
        dialog.setVisible(true);
    }

    // 恢复鼓点
    private void restoreBeats() {
        // 清除手敲鼓点记录
        tapTimes.clear();
        
        // 清除记录的原始BPM和偏移量
        originalBpm = null;
        originalOffset = null;
        
        // 创建进度弹窗
        Window parentWindow = SwingUtilities.getWindowAncestor(this);
        JDialog progressDialog = new JDialog(parentWindow, languageManager.getPanelText("playback.restore.beats"), Dialog.ModalityType.APPLICATION_MODAL);
        progressDialog.setLayout(new BorderLayout());
        progressDialog.setSize(300, 100);
        progressDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);

        JLabel statusLabel = new JLabel(languageManager.getPanelText("playback.restore.progress"), JLabel.CENTER);
        JProgressBar progressBar = new JProgressBar();
        progressBar.setIndeterminate(true);

        progressDialog.add(statusLabel, BorderLayout.CENTER);
        progressDialog.add(progressBar, BorderLayout.SOUTH);

        // 设置弹窗居中显示在屏幕中央
        progressDialog.setLocationRelativeTo(null);

        // 在后台线程中执行恢复鼓点操作
        SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
            @Override
            protected Void doInBackground() throws Exception {
                playController.restoreBeats();
                return null;
            }

            @Override
            protected void done() {
                progressDialog.dispose();
                try {
                    get(); // 检查是否有异常
                    // 恢复原始鼓点音量（如果之前被临时设置为0）
                    restoreOriginalBeatVolume();
                    // 显示波形图中的鼓点线条（当点击恢复鼓点时）
                    playController.showBeatLines();
                } catch (Exception e) {
                    showMessageDialog(languageManager.getString("playback.restore.error", e.getMessage()), JOptionPane.ERROR_MESSAGE);
                }
            }
        };

        worker.execute();
        progressDialog.setVisible(true);
    }

    /**
     * 恢复原始鼓点音量
     */
    private void restoreOriginalBeatVolume() {
        // 如果之前记录了原始鼓点音量，则恢复它
        if (originalBeatVolume != null) {
            System.out.println("恢复原始鼓点音量: " + originalBeatVolume);
            // 恢复鼓点音量
            playController.setBeatVolume(originalBeatVolume);
            // 注意：不直接更新UI滑块，而是通过PlaybackStateManager的监听器机制来更新
            // 清除记录的原始音量值
            originalBeatVolume = null;
        }
    }

    // 切换为正在播放图标
    private void setPlayingIcon() {
        SvgIconLoader.setButtonIcon(stopOrPlayerButton, "/ico/暂停.svg", 20, 20);
    }

    // 切换为暂停图标
    private void setPausedIcon() {
        SvgIconLoader.setButtonIcon(stopOrPlayerButton, "/ico/播放.svg", 20, 20);
    }

    // 设置当前播放的文件名
    private void setCurrentFileLabel(File file) {
        if (file != null) {
            currentFileLabel.setText(languageManager.getPanelText("playback.original.speed", file.getName()));
        } else {
            currentFileLabel.setText(languageManager.getPanelText("playback.original.speed", languageManager.getString("playback.no.file")));
        }
    }

    // 设置当前总时长显示
    private void setTotalTimeLabel(long durationMs) {
        // 时长秒转成分钟和秒进行显示
        totalTimeLabel.setText(formatTime(durationMs));
    }

    // 设置当前播放时间显示
    private void setCurrentTimeLabel(long currentPlaybackMs) {
        currentTimeLabel.setText(formatTime(currentPlaybackMs));
        // 只有在用户没有拖动滑块时才更新滑块位置
        if (!isSliderDragging) {
            long totalDurationMs = playbackStateManager.getTotalDurationMs();
            if (totalDurationMs > 0) {
                int sliderValue = (int) (currentPlaybackMs * playbackSlider.getMaximum() / totalDurationMs);
                playbackSlider.setValue(sliderValue);
            }
        }
    }


    /**
     * 处理手敲鼓点点击事件
     */
    private void handleTapBeat() {
        System.out.println(languageManager.getString("playback.log.tap.beat.clicked"));
        
        if (playbackStateManager.getCurrentFile() == null) {
            System.out.println(languageManager.getString("playback.log.no.playing.file"));
            return;
        }

        // 获取系统时间（纳秒）用于BPM计算
        long systemTimeNs = System.nanoTime();
        // 使用PlaybackStateManager获取当前播放位置用于偏移计算
        long currentPosition = playbackStateManager.getCurrentPositionMs();
        System.out.println(languageManager.getString("playback.log.current.position", currentPosition));
        System.out.println(languageManager.getString("playback.log.system.time", systemTimeNs));

        // 减去100ms的延迟补偿
        currentPosition -= 100;
        if (currentPosition < 0) {
            currentPosition = 0;
        }
        System.out.println(languageManager.getString("playback.log.compensated.position", currentPosition));

        // 如果是第一次点击，记录播放位置用于偏移计算，并记录原始BPM和偏移量
        if (tapTimes.isEmpty()) {
            // 记录原始BPM和偏移量
            if (originalBpm == null) {
                originalBpm = playbackStateManager.getBpm();
            }
            if (originalOffset == null) {
                originalOffset = playbackStateManager.getBeatOffset();
            }
            
            // 将播放位置作为第一个元素存储（使用负数标识这是播放位置）
            tapTimes.add(-currentPosition);
            System.out.println(languageManager.getString("playback.log.first.tap.position", currentPosition));
            
            // 记录当前鼓点音量并设置为0
            if (originalBeatVolume == null) {
                originalBeatVolume = playbackStateManager.getBeatVolume();
                System.out.println(languageManager.getString("playback.log.record.original.volume", originalBeatVolume));
                // 设置鼓点音量为0
                playController.setBeatVolume(0f);
                // 注意：不直接更新UI滑块，而是通过PlaybackStateManager的监听器机制来更新
                
                // 隐藏波形图中的鼓点线条（当用户第一次手敲鼓点时）
                playController.hideBeatLines();
            }
        }
        
        // 将系统时间加入数组（用于BPM计算）
        tapTimes.add(systemTimeNs);
        System.out.println(languageManager.getString("playback.log.recorded.tap.time", tapTimes.size()));

        if (tapTimes.size() >= 3) { // 需要至少两次间隔才能计算BPM
            System.out.println(languageManager.getString("playback.log.multiple.tap.mode"));
            // 多次敲击时，根据敲击之间的间隔计算众数，得到bpm
            java.util.List<Long> intervals = new java.util.ArrayList<>();
            for (int i = 1; i < tapTimes.size(); i++) {
                // 只计算系统时间之间的间隔（跳过第一个播放位置）
                if (tapTimes.get(i) > 0 && (i == 1 || tapTimes.get(i-1) > 0)) {
                    long interval = tapTimes.get(i) - tapTimes.get(i - 1);
                    intervals.add(interval);
                    System.out.println(languageManager.getString("playback.log.interval", i, interval));
                }
            }

            if (!intervals.isEmpty()) {
                int calculatedBpm = calculateBpmByMode(intervals);
                System.out.println(languageManager.getString("playback.log.calculated.bpm", calculatedBpm));
                // 更新BPM输入框（但不调用控制器）
                bpmInputField.setText(String.valueOf(calculatedBpm));
                System.out.println(languageManager.getString("playback.log.updated.bpm.field"));
            }
        }
        
        // 点击一次时或多次点击后，根据第一次点击时的播放位置和当前BPM计算偏移
        if (tapTimes.size() >= 1) {
            // 获取第一次点击时记录的播放位置（第一个元素是负数表示播放位置）
            long firstPosition = -tapTimes.get(0);
            double currentBpm = playbackStateManager.getBpm();
            System.out.println(languageManager.getString("playback.log.first.tap.position", firstPosition));
            System.out.println(languageManager.getString("playback.log.current.bpm", currentBpm));
            
            if (currentBpm > 0) {
                // 从bpm计算出间隔时长
                double beatIntervalMs = 60000.0 / currentBpm;
                System.out.println(languageManager.getString("playback.log.beat.interval", beatIntervalMs));
                // 用第一次点击位置对间隔时长取模得到偏移
                int offset = (int) (firstPosition % beatIntervalMs);
                System.out.println(languageManager.getString("playback.log.calculated.offset", offset));
                // 更新偏移输入框（但不调用控制器）
                offsetInputField.setText(String.valueOf(offset));
                System.out.println(languageManager.getString("playback.log.updated.offset.field"));
            } else {
                // 如果当前没有BPM值，则直接使用第一次点击位置作为偏移
                System.out.println(languageManager.getString("playback.log.no.bpm.use.position", firstPosition));
                offsetInputField.setText(String.valueOf(firstPosition));
                System.out.println(languageManager.getString("playback.log.updated.offset.field"));
            }
        }
    }

    /**
     * 使用众数统计方法计算BPM
     */
    private int calculateBpmByMode(java.util.List<Long> intervals) {
        System.out.println("开始计算BPM，间隔列表: " + intervals);
        // 将纳秒转换为毫秒的容差
        final long TOLERANCE_NS = 10000000; // 10毫秒容差
        java.util.Map<Long, Integer> intervalCounts = new java.util.HashMap<>();

        for (Long interval : intervals) {
            boolean found = false;
            for (Long existingInterval : intervalCounts.keySet()) {
                // 使用纳秒容差
                if (Math.abs(interval - existingInterval) <= TOLERANCE_NS) {
                    intervalCounts.put(existingInterval, intervalCounts.get(existingInterval) + 1);
                    found = true;
                    break;
                }
            }

            if (!found) {
                intervalCounts.put(interval, 1);
            }
        }
        
        System.out.println("间隔计数: " + intervalCounts);

        long modeInterval = 0;
        int maxCount = 0;

        for (java.util.Map.Entry<Long, Integer> entry : intervalCounts.entrySet()) {
            if (entry.getValue() > maxCount) {
                maxCount = entry.getValue();
                modeInterval = entry.getKey();
            }
        }
        
        System.out.println("众数间隔: " + modeInterval + " ns, 出现次数: " + maxCount);

        long totalInterval = 0;
        int count = 0;

        for (Long interval : intervals) {
            // 使用纳秒容差
            if (Math.abs(interval - modeInterval) <= TOLERANCE_NS) {
                totalInterval += interval;
                count++;
            }
        }
        
        System.out.println("用于计算平均值的间隔总和: " + totalInterval + " ns, 数量: " + count);

        // 将纳秒转换为毫秒计算BPM
        double averageIntervalMs = (double) totalInterval / count / 1000000.0;
        System.out.println("平均间隔: " + averageIntervalMs + " ms");
        double bpm = 60000.0 / averageIntervalMs;
        System.out.println("计算得到的BPM: " + bpm);
        int result = (int) Math.round(bpm);
        System.out.println("四舍五入后的BPM: " + result);
        return result;
    }

    /**
     * 解析BPM表达式
     */
    private double parseBpmExpression(String expression) throws NumberFormatException {
        expression = expression.trim();
        
        // 检查表达式是否为空
        if (expression.isEmpty()) {
            throw new NumberFormatException("BPM表达式不能为空");
        }

        if (expression.contains("*")) {
            String[] parts = expression.split("\\*");
            if (parts.length == 2) {
                try {
                    double operand1 = Double.parseDouble(parts[0].trim());
                    double operand2 = Double.parseDouble(parts[1].trim());
                    
                    // 检查操作数是否为正数
                    if (operand1 <= 0 || operand2 <= 0) {
                        throw new NumberFormatException("乘法表达式的操作数必须大于0");
                    }
                    
                    double result = operand1 * operand2;
                    return normalizeBpmToRange(result);
                } catch (NumberFormatException e) {
                    throw new NumberFormatException("无效的乘法表达式: " + expression);
                }
            } else {
                throw new NumberFormatException("无效的乘法表达式: " + expression);
            }
        } else {
            double bpm = Double.parseDouble(expression);
            return normalizeBpmToRange(bpm);
        }
    }

    /**
     * 将BPM值归一化到60-220范围内
     */
    private double normalizeBpmToRange(double bpm) {
        // 检查BPM是否为正数
        if (bpm <= 0) {
            throw new IllegalArgumentException("BPM值必须大于0");
        }
        
        while (bpm < 60) {
            bpm *= 2;
        }

        while (bpm > 220) {
            bpm /= 2;
        }

        return bpm;
    }

    /**
     * 更新BPM输入框的显示值
     */
    private void updateBpmInputField() {
        try {
            String input = bpmInputField.getText().trim();
            if (!input.isEmpty()) {
                double parsedBpm = parseBpmExpression(input);
                bpmInputField.setText(String.valueOf(parsedBpm));
            }
        } catch (NumberFormatException e) {
            JOptionPane.showMessageDialog(this, languageManager.getString("playback.bpm.input.error", e.getMessage()), languageManager.getString("panel.common.warning.title"), JOptionPane.WARNING_MESSAGE);
        } catch (IllegalArgumentException e) {
            JOptionPane.showMessageDialog(this, languageManager.getString("playback.bpm.value.invalid", e.getMessage()), languageManager.getString("panel.common.warning.title"), JOptionPane.WARNING_MESSAGE);
        } catch (Exception e) {
            JOptionPane.showMessageDialog(this, languageManager.getString("playback.bpm.update.error", e.getMessage()), languageManager.getString("panel.common.error.title"), JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * 格式化时间
     */
    private String formatTime(long millisecond) {
        long minutes = millisecond / 60000;
        long secs = millisecond % 60000 / 1000;
        return String.format("%02d:%02d", minutes, secs);
    }
    
    /**
     * 加载保存的音量设置
     * @return 保存的音量值(0.0-1.0)
     */
    private float loadSavedVolume() {
        try {
            luke.core.config.AppDataManager appDataManager = luke.core.config.AppDataManager.getInstance();
            return appDataManager.getVolume();
        } catch (Exception e) {
            // 如果加载失败，返回默认音量值
            return 1.0f;
        }
    }
    
    /**
     * 加载保存的节拍音量设置
     * @return 保存的节拍音量值(0.0-1.0)
     */
    private float loadSavedBeatVolume() {
        try {
            luke.core.config.AppDataManager appDataManager = luke.core.config.AppDataManager.getInstance();
            return appDataManager.getBeatVolume();
        } catch (Exception e) {
            // 如果加载失败，返回默认节拍音量值
            return 1.0f;
        }
    }
    
    /**
     * 加载保存的节拍音效类型
     * @return 保存的节拍音效类型(0-3)
     */
    private int loadSavedBeatSoundType() {
        try {
            luke.core.config.AppDataManager appDataManager = luke.core.config.AppDataManager.getInstance();
            return appDataManager.getBeatSoundType();
        } catch (Exception e) {
            // 如果加载失败，返回默认节拍音效类型
            return 0;
        }
    }
    
    /**
     * 加载保存的背景音量设置
     * @return 保存的背景音量值(0.0-1.0)
     */
    private float loadSavedBackgroundVolume() {
        try {
            luke.core.config.AppDataManager appDataManager = luke.core.config.AppDataManager.getInstance();
            return appDataManager.getBackgroundVolume();
        } catch (Exception e) {
            // 如果加载失败，返回默认背景音量值
            return 1.0f;
        }
    }
}